package com.biodiv.miracle.support.utils;

import com.biodiv.miracle.aop.aspect.AspectObject;
import com.biodiv.miracle.support.annotation.After;
import com.biodiv.miracle.support.annotation.Around;
import com.biodiv.miracle.support.annotation.Before;
import com.biodiv.miracle.support.annotation.Component;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Author: tianquan
 * @CreateTime: 2025-05-28  22:48
 * @Description: 注解工具类
 */
public class AnnotationUtils {

    /**
     * 扫描类上是否有Component注解
     *
     * @param clazz 类对象。
     * @return 匹配的注解对应的bean名称。
     */
    public static boolean scanComponentClass(Class<?> clazz) {
        if (clazz.isInterface()) {
            return false;
        }
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            boolean isComponent = hasMetaAnnotation(annotation.annotationType(), Component.class);
            if (isComponent) {
                return true;
            }
        }
        return false;
    }

    /**
     * 解析方法上的注解。
     *
     * @param method     方法对象。
     * @param annotation 注解类。
     * @return 注解对象。
     */
    public static <T extends Annotation> T parseMethod(Method method, Class<T> annotation) {
        return method.getAnnotation(annotation);
    }

    /**
     * 检查注解的值是否为空，并验证注解的方法名称是否与传入的方法名称一致。
     *
     * @param annotation 注解对象。
     * @param methodName 方法名称。
     */
    public static void annotationException(Annotation annotation, String methodName) {
        Object invoke = null;
        try {
            invoke = annotation.getClass().getMethod("value").invoke(annotation);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (invoke == null) {
            throw new RuntimeException("The value of the annotation cannot be empty");
        }
        if (!invoke.toString().replace("()", "").equals(methodName)) {
            throw new RuntimeException("The tangent method name is different from the tangent method name");
        }
    }

    /**
     * 检查AOP实体中的注解方法是否正确。
     *
     * @param aspectObject AOP实体。
     * @param methodName   方法名称。
     */
    public static void cheekAnnotation(AspectObject aspectObject, String methodName) {
        Method beforeMethod = aspectObject.getBeforeMethod();
        Method afterMethod = aspectObject.getAfterMethod();
        Method aroundMethod = aspectObject.getAroundMethod();
        if (beforeMethod != null) {
            AnnotationUtils.annotationException(beforeMethod.getAnnotation(Before.class), methodName);
        }
        if (afterMethod != null) {
            AnnotationUtils.annotationException(afterMethod.getAnnotation(After.class), methodName);
        }
        if (aroundMethod != null) {
            AnnotationUtils.annotationException(aroundMethod.getAnnotation(Around.class), methodName);
        }
    }

    /**
     * 判断某个注解是否递归包含指定的注解
     *
     * @param annotationType   要检查的注解类型（如 @Controller.class）
     * @param targetAnnotation 要查找的目标注解类型（如 @Component.class）
     * @return 如果包含目标注解，返回 true，否则返回 false
     */
    public static boolean hasMetaAnnotation(Class<? extends Annotation> annotationType, Class<? extends Annotation> targetAnnotation) {
        Set<Class<? extends Annotation>> visited = new HashSet<>();
        if (annotationType.equals(targetAnnotation)) {
            return true;
        }
        return hasMetaAnnotation(annotationType, targetAnnotation, visited);
    }

    /**
     * 判断某个注解是否递归包含指定的注解
     *
     * @param targetClass      要检查的类
     * @param targetAnnotation 要查找的目标注解类型（如 @Component.class）
     * @return 如果包含目标注解，返回 true，否则返回 false
     */
    public static boolean hasClassMetaAnnotation(Class<?> targetClass, Class<? extends Annotation> targetAnnotation) {
        Set<Class<? extends Annotation>> visited = new HashSet<>();
        Annotation[] annotations = targetClass.getAnnotations();
        for (Annotation annotation : annotations) {
            if (hasMetaAnnotation(annotation.annotationType(), targetAnnotation, visited)) {
                return true;
            }
            visited = new HashSet<>();
        }
        return false;
    }

    private static boolean hasMetaAnnotation(Class<? extends Annotation> annotationType,
                                             Class<? extends Annotation> targetAnnotation,
                                             Set<Class<? extends Annotation>> visited) {
        if (annotationType == null || targetAnnotation == null) {
            return false;
        }
        if (annotationType.equals(targetAnnotation)) {
            return true;
        }
        // 防止循环引用导致无限递归
        if (visited.contains(annotationType)) {
            return false;
        }
        visited.add(annotationType);
        // 获取当前注解的所有元注解
        for (Annotation metaAnnotation : annotationType.getDeclaredAnnotations()) {
            Class<? extends Annotation> metaAnnotationType = metaAnnotation.annotationType();
            // 如果当前元注解就是目标注解，返回 true
            if (metaAnnotationType.equals(targetAnnotation)) {
                return true;
            }
            // 递归检查该元注解的元注解
            if (hasMetaAnnotation(metaAnnotationType, targetAnnotation, visited)) {
                return true;
            }
        }
        return false;
    }

    public static <T extends Annotation> List<T> getAnnotations(Class<?> clazz, Class<T> annotationType) {
        List<T> result = new ArrayList<>();
        // 直接获取指定类型的注解（包括重复注解）
        for (T annotation : clazz.getAnnotationsByType(annotationType)) {
            result.add(annotation);
        }
        // 递归处理所有注解的注解（排除元注解）
        for (Annotation annotation : clazz.getAnnotations()) {
            Class<? extends Annotation> annotationClass = annotation.annotationType();
            if (isMetaAnnotation(annotationClass)) {
                continue; // 跳过常见元注解
            }
            result.addAll(getMetaAnnotations(annotationClass, annotationType));
        }
        return result;
    }

    // 递归查找注解的注解
    private static <T extends Annotation> List<T> getMetaAnnotations(Class<? extends Annotation> annotationClass, Class<T> targetAnnotationType) {
        List<T> result = new ArrayList<>();
        // 直接检查当前注解是否有目标注解
        if (annotationClass.isAnnotationPresent(targetAnnotationType)) {
            result.add(annotationClass.getAnnotation(targetAnnotationType));
        }
        // 递归检查注解的注解（排除元注解）
        for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
            Class<? extends Annotation> metaAnnotationClass = metaAnnotation.annotationType();
            if (isMetaAnnotation(metaAnnotationClass)) {
                continue;
            }
            result.addAll(getMetaAnnotations(metaAnnotationClass, targetAnnotationType));
        }
        return result;
    }

    // 判断是否为常见元注解
    private static boolean isMetaAnnotation(Class<? extends Annotation> annotationClass) {
        return annotationClass.equals(Annotation.class) ||
                annotationClass.equals(Target.class) ||
                annotationClass.equals(Retention.class) ||
                annotationClass.equals(Documented.class) ||
                annotationClass.equals(Inherited.class) ||
                annotationClass.equals(Repeatable.class);
    }

}
